
#include "platform.h"
#include "cm_time.h"
#include "logfile.h"
#include "cm_time.h"
#include "uart_printf.h"
#include "user_nv.h"
#include "proto_plat.h"

#include "tcp_api_01.h" 
#include "iotv30_tcp_client.h" 

#include "dev_4g.h"



#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define STR_LEN(s) (sizeof(s) - 1)
#define STR_ITEM(s) (s), STR_LEN(s)     

cat1_handle_t hcat1={
    .network_state=network_init,
    .tx_idle=1,
};

extern volatile uint32_t gtime_ms;
char   connect_err[64];
//static uint32_t last_conn_time;
static int8_t network_status_get(void);
//static int8_t network_connect(net_addr_t* paddr);



//// 让4g模块重新连接
void cat1_reconnect(char* error)
{
     LOG_NAME();

    if(strncmp(connect_err,error,64)!=0){//避免重复记录，频繁写flash
        strncpy(connect_err,error,64);
        logfile_write(1, "connection lost, errno=%s, reconnecting...", error);
    }

    hcat1.network_state=network_init;

    //TCP_Reset( );  /////dan  
    iotv30_TCP_Reset();

}










//static int8_t network_connect(viod)   //bug  code 
static int8_t network_connect(void)   //debug     viod 
{
    //TCP_Reset( );  /////dan
    iotv30_TCP_Reset();
     return 1;

}




static inline void cat1_clear_err(void)
{
    memset(connect_err,0,sizeof(connect_err));
}


/////监测4g模块的网络连接状态----
////根据4g模块实时状态---刷4g模块信息--或者 重新连接
void cat1_state_machine(void)
{

#if 0

    switch(hcat1.network_state)
    {
    case network_init:
    {
        //如果模块已经连接成功，则设置4g模块的时区，并获取4g模块信息---
        if( network_status_get() )
        {
            hcat1.network_state = network_ready;
        }
        
    } break;

    case network_ready:
        if(!last_conn_time || (last_conn_time && get_runtime() - last_conn_time > 10000)){
            if(network_connect(&server_addr)){
                hcat1.network_state = network_wait_connect;
                last_conn_time = get_runtime();
            }
        }
    break;

    case network_wait_connect:
        if(hcat1.socket){
            logfile_write(1, "connected to %s:%d", server_addr.ip, server_addr.port);
            hcat1.network_state = network_connected;  
            // last_conn_time = 0;
        }
    break;

    case network_connected:
        if(hcat1.rxlen)
        {
            cat1_clear_err();
            cm_log_printf(0,"cat1 rxlen %d\n",hcat1.rxlen);
            tlv_recv_handler(hcat1.rxbuf, hcat1.rxlen, 0);   ///////------上行协议的核心处理句柄----------------------
            hcat1.rxlen = 0;
        }
    break;

    default:
        break;
    }

#endif

}



static const char GPRS_ICCID[24]={"89860405191830308726"};
//static const char GPRS_IMEI[20]={"864999046448773"};
//static const char GPRS_IMEI[20]={"864999046448774"};  //che
static const char GPRS_IMEI[20]={"864999046448775"};   


/**
 * @brief 初始化4g模块信息---
 * 
 * @return null
 */
 void dev_4g_init(void)
{

   memset(&hcat1 ,0,sizeof(cat1_handle_t) ) ;
    hcat1.network_state=network_init;
    hcat1.tx_idle=1;

#if 0 ///testing

   strcpy(hcat1.CCID ,GPRS_ICCID ) ;
   strcpy(hcat1.IMEI ,GPRS_IMEI) ;//////IMEI低12位做mac，用于平台管理

   hcat1.CSQ = 28;// 2...30 – -109... -53 dBm
////<rssi>
// 0 – -113 dBm or less
// 1 – -111 dBm
// 2...30 – -109... -53 dBm
// 31 – -51 dBm or greater
// 99 – not known or not detectable


   hcat1.BER = 7;  // 7 – >=8.0%
// <ber>
// (in percent)
// 0 – <0.01%
// 1 – 0.01% --- 0.1%
// 2 – 0.1% --- 0.5%
// 3 – 0.5% --- 1.0%
// 4 – 1.0% --- 2.0%
// 5 – 2.0% --- 4.0%
// 6 – 4.0% --- 8.0%
// 7 – >=8.0%
// 99 – not known or not detectable



   strcpy(hcat1.SN ,"01234567890123456789012345678901") ;
   strcpy(hcat1.IMSI ,"0123456789012345") ;
   strcpy(hcat1.COPS ,"01234567890123456789012345678901") ;

    // char SN[32+1];
    // char IMEI[IMEI_STR_LEN];
    // char IMSI[15+1];
    // char CSQ;
    // char BER;
    // char CCID[ICCID_STR_LEN];
    // char COPS[32+1];

#endif

}




/**
 * @brief 获取网络连接状态
 * 
 * @return int8_t 1，连接成功， 0，正常尝试连接
  如果模块已经连接成功，则设置4g模块的时区，并获取4g模块信息---
 */
static int8_t network_status_get(void)
{
      LOG_NAME();

		//已经联网ok,则设置4g模块的时区，并获取4g模块信息---

        timezone_set(); ////设置时区

#if 0
        cm_tm_t t;
        cm_sec_to_date((uint32_t)(cm_rtc_get_current_time() + cm_rtc_get_timezone() * 60 * 60), &t);////时间戳转换为日期格式
        ////打印时间日期 log
        cm_log_printf(0,"time:%d-%d-%d:%d:%d:%d,%s\n", 
                      t.tm_year, t.tm_mon , t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,weekday_str[cm_time_to_weekday(&t)-1]);
#endif       


        ///////刷新 SN--- //获取模组SN
     
        cm_log_printf(0,"network ready\n");
        
        return 1;

}


#if   0     /////dan-----如果模块已经连接成功，则设置4g模块的时区，并获取4g模块信息-----


/**
 * @brief 获取网络连接状态
 * 
 * @return int8_t 1，连接成功， 0，正常尝试连接
  如果模块已经连接成功，则设置4g模块的时区，并获取4g模块信息---
 */
static int8_t network_status_get(void)
{
    static uint32_t time,cnt; 
    static int rf_csq;

    if(time_intval(time) < 1000){
        return 0;
    }
    time = get_runtime();

    if(cm_modem_get_pdp_state(1) == 1)///////获取4g模块联网状态 
    {
		//已经联网ok,则设置4g模块的时区，并获取4g模块信息---

        timezone_set(); ////设置时区

        cm_tm_t t;
        cm_sec_to_date((uint32_t)(cm_rtc_get_current_time() + cm_rtc_get_timezone() * 60 * 60), &t);////时间戳转换为日期格式
        ////打印时间日期 log
        cm_log_printf(0,"time:%d-%d-%d:%d:%d:%d,%s\n", 
                      t.tm_year, t.tm_mon , t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,weekday_str[cm_time_to_weekday(&t)-1]);
        
        ///////刷新 SN--- //获取模组SN
        if (cm_sys_get_sn(hcat1.SN) == 0){
            cm_log_printf(0,"SN:%s\n", hcat1.SN);
        }else{
            memset(hcat1.SN, 0, sizeof(hcat1.SN));
        }
        
        if (cm_sys_get_imei(hcat1.IMEI) == 0){
            cm_log_printf(0,"IMEI:%s\n", hcat1.IMEI);
        }else{
            memset(hcat1.IMEI, 0, sizeof(hcat1.IMEI));
        }

        if (cm_sim_get_imsi(hcat1.IMSI) == 0){
            cm_log_printf(0,"IMSI:%s\n", hcat1.IMEI);
        }else{
            memset(hcat1.IMSI, 0, sizeof(hcat1.IMSI));
        }

        char rsp[256]={0};
        int32_t rsp_len;

        //////通过AT虚拟通道同步获取数据
        if(cm_virt_at_send_sync((const uint8_t *)"AT+CSQ\r\n", (uint8_t*)rsp, &rsp_len, 32) == 0){
            char* p=strstr(rsp,"+CSQ");
            if(p){
                int a,b;
                uint8_t ret = sscanf(p,"+CSQ:%d,%d", &a, &b);/////提取CSQ,BER 数据
                if(ret==2){
                    hcat1.CSQ = (char)a;   /////提取CSQ,BER 数据
                    hcat1.BER = (char)b;
                }else{
                    hcat1.CSQ = 0;
                    hcat1.BER = 0;
                }

                if(rf_csq != a){
                    rf_csq = a;
                    logfile_write(1,"cat1 connected, CSQ:%d,BER:%d",hcat1.CSQ,hcat1.BER);
                }
            }
        }

        memset(rsp, 0, sizeof(rsp));
        if(cm_virt_at_send_sync((const uint8_t*)"AT+CRSM=176,12258,0,0,10\r\n",(uint8_t*)rsp, &rsp_len, 100) == 0)
        {
            char* p = strstr(rsp,"\"");
            if(p){
                p++;
                for(uint8_t i=0;i<10;i++){
                    hcat1.CCID[2*i+0] = p[2*i+1];
                    hcat1.CCID[2*i+1] = p[2*i+0];
                }
                hcat1.CCID[20] = '\0';
                cm_log_printf(0,"CCID:%s\n", hcat1.CCID);/////提取CCID 数据
            }else{
                memset(hcat1.CCID, 0, sizeof(hcat1.CCID));
            }
        }

        if(cm_virt_at_send_sync((const uint8_t*)"AT+COPS?\r\n",(uint8_t*)rsp, &rsp_len, 700) == 0)
        {
            char* p = strstr(rsp,"\"");
            if(p){
                p++;
                for(uint8_t i=0;i<32;i++){
                    if(p[i] == '\0' || p[i] == '\"'){
                        hcat1.COPS[i] = '\0';          ////提取 COPS 数据
                        break;
                    }
                    hcat1.COPS[i] = p[i];
                }
                hcat1.COPS[32] = '\0';
                cm_log_printf(0,"COPS:%s\n", hcat1.COPS);
            }else{
                memset(hcat1.COPS, 0, sizeof(hcat1.COPS));
            }
        }


        cm_log_printf(0,"network ready\n");
        cnt=0;        
        return 1;
    }
    else
    {////没有联网则复位4g模块

        cm_log_printf(0,"network connecting %d ...\n",cnt++);
        if(cnt > 15){
            int32_t ret=0;
            ret |= cm_virt_at_send_sync((const uint8_t*)"AT+CFUN=0\r\n", NULL, NULL, 0);
            osDelay(50);
            ret |= cm_virt_at_send_sync((const uint8_t*)"AT+CFUN=1\r\n", NULL, NULL, 0);
            osDelay(200);
            cm_log_printf(0,"network restart, ret %d\n",ret);
            cnt = 0;
            rf_csq = 0;
        }
        return 0;
    }
}





#endif

#if   0   /////dan

////------这部分都是与--通过注册事件(Event )异步发送-cat1_send_data(int8_t socket, uint8_t* data , uint16_t len)---相关的方法-------------------------
/// -----已经用  plat_send() 代替 cat1_send_data()


/********************************************************************************************* */ 
static void __on_asocket_event(int sock, cm_asocket_event_e event, void *user_param)
{
    switch (event)
    {
        // responses
        case CM_ASOCKET_EV_CONNECT_OK: 
        {
            cm_log_printf(0,"sock [%d] connect_ok\n", sock);
            hcat1.network_state = network_connected;
            break;
        }
        
        case CM_ASOCKET_EV_CONNECT_FAIL: 
        {
            cm_log_printf(0,"sock [%d] connect_fail\n", sock);
            //hcat1.network_state = network_init;
            cat1_reconnect("socket open failed");
            break;
        }

        // indications
        case CM_ASOCKET_EV_RECV_IND: 
        {
            /* 取得获取接收缓存中可读的数据长度 */
            int recv_avail = 0;
            cm_asocket_ioctl(sock, FIONREAD, &recv_avail);
            /* 接收数据 */
            int ret = cm_asocket_recv(sock, hcat1.rxbuf, sizeof(hcat1.rxbuf), 0);
            
            if (ret > 0)
            {
                hcat1.rxlen = ret;
                cm_log_printf(0,"sock [%d] recv_ind: recv_avail=%d, recv_len=%d\n", sock, recv_avail, ret);
            }
            else
            {
                cm_log_printf(0,"sock [%d] recv_ind error(%d)\n", sock, errno);
                if (ENOTCONN == errno)
                {
                    /* Connection closed */
                    cm_log_printf(0,"sock [%d] recv_ind: Connection closed\n", sock);
                    
                    //hcat1.network_state = network_init;
                    cat1_reconnect("not connect");
                }
            }
            break;
        }
        
        case CM_ASOCKET_EV_SEND_IND:
        {
            //cm_log_printf(0,"sock [%d] send_ind\n", sock);
            cm_log_printf(0,"sock [%d] send finished\n", sock);
            hcat1.tx_idle = 1;
            break;
        }
            
        case CM_ASOCKET_EV_ACCEPT_IND:
        {
            cm_log_printf(0,"sock [%d] accept_ind\n", sock);
            break;
        }

        case CM_ASOCKET_EV_ERROR_IND: 
        {
            /* 获取socket错误码 */
            int sock_error = 0;
            socklen_t opt_len = sizeof(sock_error);
            
            cm_asocket_getsockopt(sock, SOL_SOCKET, SO_ERROR, &sock_error, &opt_len);
            cm_log_printf(0,"sock [%d] error_ind: sock_error [%d]\n", sock, sock_error);
            
            if (ECONNABORTED == sock_error)
            {
                /* Connection aborted */
                cm_log_printf(0,"sock [%d] error_ind: Connection aborted\n", sock);
                
                //hcat1.network_state = network_init;
                cat1_reconnect("connection abort");
            }
            else if (ECONNRESET == sock_error)
            {
                /* Connection reset */
                cm_log_printf(0,"sock [%d] error_ind: Connection reset\n", sock);
                
                //hcat1.network_state = network_init;
                cat1_reconnect("connection reset");
            }
            else if (ENOTCONN == sock_error)
            {
                /* Connection closed */
                cm_log_printf(0,"sock [%d] error_ind: Connection closed\n", sock);

                //hcat1.network_state = network_init;
                cat1_reconnect("connection closed");
            }else{
                cm_log_printf(0,"sock [%d] error_ind, not handled!!!", sock);
            }
            break;
        }
        
        default:
        {
            cm_log_printf(0,"sock [%d] shoud not be here!", sock);
            break;
        }
    }
}

static void __on_eloop_cmd_OPEN_recv_event(cm_eloop_event_handle_t event, void *cb_param)
{
    /* 注销Event */
    cm_eloop_unregister_event(event);

    int sock = -1;
    /* TCP */
    sock = cm_asocket_open(AF_INET, SOCK_STREAM, IPPROTO_TCP, __on_asocket_event, NULL);    
    /* UDP */
//  sock = cm_asocket_open(AF_INET, SOCK_DGRAM, IPPROTO_UDP, __on_asocket_event, NULL);
    if (-1 == sock)
    {
        cm_log_printf(0,"open failed\n");
        hcat1.socket = -1;
        cat1_reconnect("socket open failed");
        return;
    }

    cm_log_printf(0,"sock [%d] open\n", sock);
    hcat1.socket = sock;
    
    net_addr_t* p = (net_addr_t*)cb_param;

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(p->ip);
    server_addr.sin_port = htons(p->port);
    int ret = cm_asocket_connect(sock, (const struct sockaddr *)&server_addr, sizeof(server_addr));
    
    if (ret < 0)
    {
        if (EINPROGRESS == errno)
        {
            cm_log_printf(0,"sock [%d] open request success, wait connect...\n", sock);
        }
        else
        {
            cm_log_printf(0,"sock [%d] connect failed(%d)\n", sock, errno);
        }
    }
    else if (0 == ret)
    {
        cm_log_printf(0,"sock [%d] connect_ok\n", sock);
        hcat1.network_state = network_connected;
    }
}

static void __on_cmd_OPEN(void *param)
{
    net_addr_t* paddr = (net_addr_t*)param;

    cm_log_printf(0,"socket open tcp: %s, %d\n", paddr->ip, paddr->port);
    /* 注册Event(将命令封装成Event发送到eloop执行) */
    cm_eloop_event_handle_t cmd_OPEN_recv_event = cm_eloop_register_event(cm_asocket_eloop(), __on_eloop_cmd_OPEN_recv_event, paddr);
    /* 发送到eloop执行 */
    cm_eloop_post_event(cmd_OPEN_recv_event);
} 


static void __on_eloop_cmd_CLOSE_recv_event(cm_eloop_event_handle_t event, void *cb_param)
{
    /* 注销Event */
    cm_eloop_unregister_event(event);

    int8_t socket = *(int8_t*)cb_param;

    //cm_log_printf(0,"__on_eloop_cmd_CLOSE_recv_event sock=%d\n", *cb_param);

    /* 处理命令 */
    int ret = cm_asocket_close(socket);
    
    if (0 == ret)
    {
        cm_log_printf(0, "sock [%d] close success\n", socket);
    }
    
    else
    {
        cm_log_printf(0, "sock [%d] close error(%d)\n", socket, errno);
    }
}



static void __on_cmd_CLOSE(int8_t socket)
{
    /* 处理参数 */
//    cm_log_printf("__on_cmd_CLOSE sock=%d\n", socket);

    /* 注册Event(将命令封装成Event发送到eloop执行) */
    cm_eloop_event_handle_t cmd_CLOSE_recv_event = cm_eloop_register_event(cm_asocket_eloop(), __on_eloop_cmd_CLOSE_recv_event, &socket);
    /* 发送到eloop执行 */
    cm_eloop_post_event(cmd_CLOSE_recv_event);
}


static int8_t network_connect(net_addr_t* paddr)
{
    if(hcat1.socket){
        __on_cmd_CLOSE(hcat1.socket);
        osDelay(100);
        hcat1.socket = 0;
        return 0;
    }else{
        __on_cmd_OPEN(paddr);
        return 1;
    }
}

/************************************************************************************** */
typedef struct{
    char socket;
    uint8_t* buf;
    uint16_t len;
}send_param_t;

static void __on_eloop_cmd_SEND_recv_event(cm_eloop_event_handle_t event, void *cb_param)
{
    send_param_t* param = (send_param_t*)cb_param;

    /* 注销Event */
    cm_eloop_unregister_event(event);

    int ret = cm_asocket_send(param->socket, param->buf, param->len, 0);

    //cm_demo_printf("__on_eloop_cmd_SEND_recv_event sock=%d\n", sock);

    // if (ret > 0)
    // {
    //     cm_log_printf(0,"sock(%d) send len=%d\n", param->socket, param->len);
    // }
    // else
    // {
    //     cm_log_printf(0,"sock(%d) send error(%d)\n", param->socket, ret);
    // }

    if (ret <= 0)
    {
        cm_log_printf(0,"sock [%d] send error [%d]\n", param->socket, ret);
    }
}






////通过注册事件(Event )异步发送---
void cat1_send_data(int8_t socket, uint8_t* data , uint16_t len)
{
    send_param_t param={
        .socket=socket,
        .buf=data,
        .len=len,
    };
    cm_log_printf(0,"send sock [%d] len [%d] start\n", socket, len);

    /* 注册Event(将命令封装成Event发送到eloop执行) */
    cm_eloop_event_handle_t cmd_SEND_recv_event = cm_eloop_register_event(cm_asocket_eloop(), __on_eloop_cmd_SEND_recv_event, &param);
    /* 发送到eloop执行 */
    cm_eloop_post_event(cmd_SEND_recv_event);

    hcat1.tx_idle = 0;

    for(uint8_t i=0;i<100;i++){
        if(hcat1.tx_idle){
            break;
        }
        osDelay(1);//os tick=5ms, 实际上的最大delay为500ms
    }
}



#endif



